﻿using System;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Xml;
using System.Xml.Serialization;
using Logistics.Web.Models.Checkout;
using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Logistics;
using Nop.Services.Common;
using Nop.Services.Localization;
using Nop.Services.Logging;
using Nop.Services.Logistics;
using Nop.Services.Payments;

namespace Logistics.Web.Controllers
{
    public class CheckoutController : BaseController
    {
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly IWorkContext _workContext;
        private readonly LogisticsInformationSettings _logisticsInformationSettings;
        private readonly IOrderProcessingService _orderProcessingService;
        private readonly HttpContextBase _httpContext;
        private readonly ILogger _logger;
        private readonly ILocalizationService _localizationService;

        public CheckoutController(
            IGenericAttributeService genericAttributeService,
            ILocalizationService localizationService,
            IWorkContext workContext,
            LogisticsInformationSettings logisticsInformationSettings,
            IOrderProcessingService orderProcessingService,
            HttpContextBase httpContext,
            ILogger logger
            )
        {
            this._genericAttributeService = genericAttributeService;
            this._localizationService = localizationService;
            this._workContext = workContext;
            this._logisticsInformationSettings = logisticsInformationSettings;
            this._orderProcessingService = orderProcessingService;
            this._httpContext = httpContext;
            this._logger = logger;
        }

        [ChildActionOnly]
        public ActionResult PaymentInfo()
        {
            var model = new PaymentInfoModel()
            {
                DebugEnabled = _logisticsInformationSettings.GpDebug
            };

            try
            {
                model.SecureFrameUrl = string.Format("<iframe id=\"secureFrame\" class=\"secureFrame\" src=\"{0}\"></iframe>", GenerateSecureFrameUrl());
            }
            catch (Exception e)
            {
                _logger.Warning(e.Message, e);
                model.Warnings.Add("Payment request information cannot be loaded.");
            }

            return View(model);
        }

        #region Helper

        private string GenerateSecureFrameUrl()
        {
            return Helper.BuildUrlWithQuery(_logisticsInformationSettings.GpGlobalPaymentUrl, GenerateQueryStrings());
        }

        private NameValueCollection GenerateQueryStrings()
        {
            var query = new NameValueCollection();
            var customer = _workContext.CurrentCustomer;
            var billingAddr = customer.BillingAddress;

            query.Add("collectAddress", "0");
            query.Add("action", "buildForm");
            query.Add("merchPass", _logisticsInformationSettings.GpMerchPass);
            query.Add("allowed_types", "Visa|MasterCard");
            query.Add("sessionId", Guid.NewGuid().ToString());
            query.Add("currency_code", "CAD");
            query.Add("formType", "1");
            query.Add("customer_id", customer.Id.ToString());
            //query.Add("callback_url", "");

            if (billingAddr != null)
            {
                if (!String.IsNullOrWhiteSpace(billingAddr.FirstName) && !String.IsNullOrWhiteSpace(billingAddr.LastName))
                {
                    query.Add("name", String.Format("{0} {1}", billingAddr.FirstName, billingAddr.LastName));
                }
                query.AddNonEmptyValue("customer_email", billingAddr.Email);
                query.AddNonEmptyValue("address", billingAddr.Address1);
                query.AddNonEmptyValue("address2", billingAddr.Address2);
                query.AddNonEmptyValue("city", billingAddr.City);
                query.AddNonEmptyValue("state", billingAddr.StateProvince.Name);
                query.AddNonEmptyValue("zip", billingAddr.ZipPostalCode);
                query.AddNonEmptyValue("country", "CA"); // TODO: Hard-coded country
            }

            var paymentProcessRequest = _orderProcessingService.LoadPaymentInformation(customer);

            var debugTotal = _logisticsInformationSettings.GpDebugTotal;
            if (debugTotal > 0)
            {
                paymentProcessRequest.OrderTotal = debugTotal.Value;
            }
            query.Add("amount", paymentProcessRequest.OrderTotal.ToString("F2", CultureInfo.InvariantCulture));
            
            return query;
        }

        #endregion
    }

    #region Helper

    public static class Helper
    {
        public static string BuildUrlWithQuery(string url, NameValueCollection queryStrs)
        {
            if (url.Last() == '/')
            {
                url = url.Remove(url.Length - 1);
            }
            StringBuilder builder = new StringBuilder();
            foreach (var key in queryStrs.Keys)
            {
                var name = key as string;
                if (!String.IsNullOrEmpty(name))
                {
                    builder.Append((builder.Length == 0) ? "?" : "&")
                        .Append(HttpUtility.UrlEncode(name))
                        .Append("=")
                        .Append(HttpUtility.UrlEncode(queryStrs[name]));
                }
            }

            return url + builder.ToString();
        }
    }

    public static class NameValueCollectionExtensions
    {
        public static void AddNonEmptyValue(this NameValueCollection nv, string name, string val)
        {
            if (!String.IsNullOrWhiteSpace(val))
            {
                nv.Add(name, val);
            }
        }
    }

    #region Response Types

    public class transaction
    {
        public long? transactionStart { set; get; }
        public long? transactionEnd { set; get; }
        public string merchantPass { set; get; }
        public string sessionId { set; get; }
        public string status { set; get; }
        public string transId { set; get; }
        public string approvalCode { set; get; }
        public string tokenId { set; get; }
        public decimal? amount { set; get; }
        public string name { set; get; }
        public address address { set; get; }
        public string customerId { set; get; }
        public string customerEmail { set; get; }
        public string cardNumber { set; get; }
        public string cardType { set; get; }
        public string cardBrandSelected { set; get; }
        public int? expMonth { set; get; }
        public int? expYear { set; get; }
        public string CVVMatch { set; get; }
        public string AVSMatch { set; get; }
        public string appCode { get; set; }
        public string ccNumber { get; set; }
        public string ccType { get; set; }
        public string paymentType { get; set; }
        public string rurl { get; set; }
    }

    public class address
    {
        public string address1 { set; get; }
        public string address2 { set; get; }
        public string city { set; get; }
        public string state { set; get; }
        public string zip { set; get; }
    }

    #endregion

    #endregion
}
